home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / XML / NITF.php < prev    next >
PHP Script  |  2004-03-24  |  20KB  |  748 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 2003-2004 TownNews.com                                 |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Patrick O'Lone <polone@townnews.com>                        |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // NITF.php,v 1.2 2003/05/29 19:02:08 polone Exp
  20.  
  21. require_once('XML/Parser.php');
  22.  
  23. /**
  24. * Generic NITF Parser class
  25. *
  26. * This class provides basic NITF parsing. Many of the major elements of the NITF
  27. * standard are supported. This implementation is based off the NITF 3.1 DTD,
  28. * publicly available at the following URL:
  29. *
  30. * http://www.nitf.org/site/nitf-documentation/nitf-3-1.dtd
  31. *
  32. * Note that not all elements of this standard are not supported.
  33. *
  34. * @author Patrick O'Lone <polone@townnews.com>
  35. * @version 1.2
  36. * @package XML
  37. */
  38. class XML_NITF extends XML_Parser
  39. {
  40.     /**
  41.     * @var array
  42.     * Document metadata. Container for metadata information about this
  43.     * particular document.
  44.     * @see getDocData()
  45.     * @access private
  46.     */
  47.     var $m_kDocData = array('key-list' => array());
  48.     
  49.     /**
  50.     * @var array
  51.     * Information about specific instance of an item's publication. Contains
  52.     * metadata about how the particular news object was used in a specific
  53.     * instance.
  54.     * @see getPubData()
  55.     * @access private
  56.     */
  57.     var $m_kPubData = array();
  58.     
  59.     /**
  60.     * @var array
  61.     * Information about the creative history of the document; also used as an
  62.     * audit trail. Includes who made changes, when the changes were made, and
  63.     * why. Each element of the array is a key-based array that corresponds to
  64.     * the <revision-history> element.
  65.     * @see getRevision()
  66.     * @access private
  67.     */
  68.     var $m_akRevisions = array();
  69.     
  70.     /**
  71.     * @var array
  72.     * The various headlines that were found in the document. The headlines are
  73.     * keyed by the levels of HLX. The default hedline (if no level is found) is
  74.     * HL1.
  75.     * @see getHedlines()
  76.     * @access private
  77.     */
  78.     var $m_kHedlines = array( 'HL1' => null, 'HL2' => array() );
  79.  
  80.     /**
  81.     * @var string
  82.     * Story abstract summary or synopsis of the contents of the document.
  83.     * @access private
  84.     */
  85.     var $m_sAbstract = null;
  86.     
  87.     /**
  88.     * @var string
  89.     * Significant place mentioned in an article. Used to normalize locations.
  90.     * The location in this variable is the place where the story's events will
  91.     * or have unfolded.
  92.     * @access private
  93.     */
  94.     var $m_sLocation = null;
  95.     
  96.     /**
  97.     * @var string
  98.     * Information distributor. May or may not be the owner or creator.
  99.     * @access private
  100.     */
  101.     var $m_sDistributor = null;
  102.  
  103.     /**
  104.     * @var string
  105.     * The elements of the byline, including the author's name and title.
  106.     * @see getByline()
  107.     * @access private
  108.     */
  109.     var $m_kByline = array( 'author' => null, 'title' => null );
  110.     
  111.     /**
  112.     * @var array
  113.     * An array of paragraphs extracted from the document
  114.     * @see getLede(), getContent()
  115.     * @access private
  116.     */
  117.     var $m_aContent = array();
  118.  
  119.     /**
  120.     * @var array
  121.     * A list of media reference elements as found in the body section of the
  122.     * document. Each element is an array itself with keyed properties related
  123.     * to media element in question.
  124.     * @see getMedia()
  125.     * @access private
  126.     */
  127.     var $m_aMedia = array();
  128.  
  129.     /**
  130.     * @var array
  131.     * A list of tags that were parsed (in order) denoting the current sequence
  132.     * of tags that were parsed. This is array is used for parsing the document
  133.     * elements in a particular order (if needed).
  134.     * @see StartHandler(), EndHandler(), cdataHandler()
  135.     * @access private
  136.     */
  137.     var $m_aParentTags = array();
  138.     
  139.     /**
  140.     * @var string
  141.     * A byline at the end of a story. Example: Stuart Myles contributed to this
  142.     * article.
  143.     * @see getTagline()
  144.     * @access private
  145.     */
  146.     var $m_sTagline = null;
  147.     
  148.     /**
  149.     * @var string
  150.     * Free-form bibliographic data. Used to elaborate on the source of
  151.     * information.
  152.     * @see getBibliography()
  153.     * @access private
  154.     */
  155.     var $m_sBibliography = null;
  156.     
  157.     /**
  158.     * Access all or specific elements of the <docdata> block
  159.     *
  160.     * @return mixed
  161.     * All of the elements from the <docdata> block will be returned if a specific
  162.     * property is not provided. If a specific property is requested and is found
  163.     * in the docdata block, then that property will be returned. If the property
  164.     * cannot be found, null is returned.
  165.     *
  166.     * @param string
  167.     * The property of the <docdata> block to return, the most common being:
  168.     *
  169.     * "doc-id" - a unique identifier of this document (string)
  170.     * "key-list" - a list of keywords provided with the document (array)
  171.     * "copyright" - the copyright holder (string)
  172.     * "series" - if the document is part of series (string)
  173.     * "urgency" - a number between 1 (urgent) and 8 (not urgent) (integer)
  174.     * "date.issue" - date the document was issued (UNIX timestamp)
  175.     * "date.release" - date the document is publicly available (UNIX timestamp)
  176.     * "date.expires" - date the document is no longer valid (UNIX timestamp)
  177.     *
  178.     * @see getDocDataElement()
  179.     * @access public
  180.     */
  181.     function getDocData( $sProperty = null )
  182.     {
  183.         if (!empty($sProperty)) {
  184.  
  185.             $sProperty = strtolower($sProperty);
  186.             if (isset($this->m_kDocData[$sProperty])) {
  187.  
  188.                 return $this->m_kDocData[$sProperty];
  189.  
  190.             }
  191.             return null;
  192.         
  193.         }
  194.         return $this->m_kDocData;
  195.     }
  196.  
  197.     /**
  198.     * Returns all elements or a specific element from the <pubdata> block
  199.     *
  200.     * @return mixed
  201.     * Returns string, numeric, or array values depending on the property being
  202.     * accessed from the <pubdata> block.
  203.     *
  204.     * @access public
  205.     */
  206.     function getPubData( $sProperty = null )
  207.     {
  208.         if (!empty($sProperty)) {
  209.  
  210.             $sProperty = strtolower($sProperty);
  211.             if (isset($this->m_kPubData[$sProperty])) {
  212.  
  213.                 return $this->m_kPubData[$sProperty];
  214.  
  215.             }
  216.             return null;
  217.  
  218.         }
  219.         
  220.         return $this->m_kPubData;
  221.     }
  222.     
  223.     /**
  224.     * Get the revision history
  225.     *
  226.     * @return array
  227.     * An array containing key-value arrays. The properties of each array element
  228.     * in this array are:
  229.     *
  230.     * "comment" - Reason for the revision
  231.     * "function" - Job function of individual performing revision
  232.     * "name" - Name of the person who made the revision
  233.     * "norm" - Date of the revision
  234.     *
  235.     * @access public
  236.     */
  237.     function getRevision()
  238.     {
  239.         return $this->m_akRevisions;
  240.     }
  241.  
  242.     /**
  243.     * Retrieve all headlines or a single headline denoted by key
  244.     *
  245.     * @return mixed
  246.     * Returns an array if no specific headline element is requested, or a string
  247.     * if the specific headline element requested exists
  248.     *
  249.     * @param string
  250.     * The key value corresponding to the headline to be retrieved
  251.     *
  252.     * @access public
  253.     */
  254.     function getHeadline( $nLevel = 1 )
  255.     {
  256.         return $this->m_kHedlines["HL$nLevel"];
  257.     }
  258.  
  259.     /**
  260.     * Return information about the author of a document
  261.     *
  262.     * @param string
  263.     * The field of the byline to retrieve.
  264.     *
  265.     * @access public
  266.     */
  267.     function getByline( $sProperty = 'author' )
  268.     {
  269.         $sProperty = strtolower($sProperty);
  270.         if (isset($this->m_kByline[$sProperty])) {
  271.  
  272.             return $this->m_kByline[$sProperty];
  273.  
  274.         }
  275.         
  276.         return null;
  277.     }
  278.     
  279.     /**
  280.     * Query for a list of related media elements
  281.     *
  282.     * @return array
  283.     * Returns an array of all media reference data, or an array of select media
  284.     * reference data determined by the property parameter passed.
  285.     *
  286.     * @param string
  287.     * If supplied, only this property will be returned for each element of the
  288.     * media reference array.
  289.     *
  290.     * @access public
  291.     */
  292.     function getMedia( $sProperty = null )
  293.     {
  294.         if (empty($sProperty)) {
  295.  
  296.            return $this->m_aMedia;
  297.  
  298.         } else {
  299.  
  300.            $aMediaRefs = array();
  301.            foreach($this->m_aMedia as $aMediaElement) {
  302.  
  303.               if (isset($aMediaElem[$sProperty])) {
  304.  
  305.                  array_push($aMediaRefs, $aMediaElem[$sProperty]);
  306.  
  307.               }
  308.            }
  309.            
  310.            return $aMediaRefs;
  311.  
  312.         }
  313.     }
  314.     
  315.     /**
  316.     * Returns the lede (sometimes called lead) paragraph
  317.     *
  318.     * @return string
  319.     * Returns the lede paragraph if it is defined, or null otherwise
  320.     *
  321.     * @access public
  322.     */
  323.     function getLede()
  324.     {
  325.         if (isset($this->m_aContent[0])) {
  326.  
  327.            return $this->m_aContent[0];
  328.  
  329.         }
  330.         return null;
  331.     }
  332.     
  333.     /**
  334.     * Returns the paragraphs of content
  335.     *
  336.     * @return array
  337.     * An array of elements that represent a single paragraph each
  338.     *
  339.     * @access public
  340.     */
  341.     function &getContent()
  342.     {
  343.         return $this->m_aContent;
  344.     }
  345.     
  346.     /**
  347.     * Returns the tag line (if one exists)
  348.     *
  349.     * @return string
  350.     * The tag line extracted from the NITF data source
  351.     *
  352.     * @access public
  353.     */
  354.     function getTagline()
  355.     {
  356.         return $this->m_sTagline;
  357.     }
  358.     
  359.     /**
  360.     * Returns the free-form bibliographic data
  361.     *
  362.     * @return string
  363.     * The bibliography (if one exists) is returned
  364.     *
  365.     * @access public
  366.     */
  367.     function getBibliography()
  368.     {
  369.         return $this->m_sBibliography;
  370.     }
  371.     
  372.     /**
  373.     * Get a string version of the article
  374.     *
  375.     * @return string
  376.     * A string representing the main headline, author, content, and tagline.
  377.     *
  378.     * @param string
  379.     * The character(s) used to separate each article element in the string that
  380.     * is returned - often referred to as the CRLF.
  381.     *
  382.     * @access public
  383.     */
  384.     function &toString( $sCRLF = "\n" )
  385.     {
  386.         $sArticle = "{$this->m_kHedlines['HL1']}$sCRLF";
  387.  
  388.         if (!empty($this->m_kByline['author'])) {
  389.  
  390.             $sArticle .= "{$this->m_kByline['author']}$sCRLF";
  391.  
  392.         }
  393.         
  394.         if (!empty($this->m_sLocation)) {
  395.  
  396.            $sArticle .= "{$this->m_sLocation} - ";
  397.  
  398.         }
  399.         
  400.         $sArticle .= join($sCRLF, $this->m_aContent);
  401.  
  402.         if (!empty($this->m_sTagline)) {
  403.  
  404.             $sArticle .= "$sCRLF{$this->m_sTagline}";
  405.             
  406.         }
  407.         
  408.         return $sArticle;
  409.     }
  410.  
  411.     /**
  412.     * Handle start XML elements and attributes
  413.     *
  414.     * When a new element is begun, this handler is executed.
  415.     *
  416.     * @param object
  417.     * The XML parser object instance that was inherited from the XML_Parser
  418.     * class
  419.     *
  420.     * @param string
  421.     * A tag element from the XML data stream
  422.     *
  423.     * @param array
  424.     * An array of XML attributes associated with the given tag supplied
  425.     *
  426.     * @access private
  427.     */
  428.     function StartHandler($oParser, $sName, $kAttrib )
  429.     {
  430.         // Push the element into the stack of XML elements already visited
  431.         
  432.         array_push($this->m_aParentTags, $sName);
  433.         
  434.         // Handle the attributes of the XML tags
  435.         
  436.         switch ($sName) {
  437.  
  438.            case 'HL2':
  439.               $this->_sHedline = null;
  440.               break;
  441.  
  442.            case 'P':
  443.               if (!empty($kAttrib['LEDE']) && ($kAttrib['LEDE'] == 'true')) {
  444.  
  445.                   $this->_bIsLede = true;
  446.  
  447.               }
  448.               $this->_sContent = null;
  449.               break;
  450.  
  451.            case 'DOC.COPYRIGHT':
  452.               $this->m_sCopyright = $kAttrib['HOLDER'];
  453.               break;
  454.               
  455.            case 'MEDIA':
  456.               $this->_kMedia = array();
  457.               if (!empty($kAttrib['MEDIA-TYPE'])) {
  458.  
  459.                   $this->_kMedia['type'] = $kAttrib['MEDIA-TYPE'];
  460.  
  461.               } else {
  462.  
  463.                   $this->_kMedia['type'] = 'other';
  464.  
  465.               }
  466.               
  467.               $this->_kMedia['source'] = null;
  468.               $this->_kMedia['mime-type'] = null;
  469.               $this->_kMedia['caption'] = null;
  470.               $this->_kMedia['data'] = null;
  471.               $this->_kMedia['encoding'] = null;
  472.               $this->_kMedia['producer'] = null;
  473.               $this->_kMedia['meta'] = array();
  474.               break;
  475.               
  476.            case 'MEDIA-REFERENCE':
  477.               if (!empty($kAttrib['SOURCE'])) {
  478.  
  479.                   $this->_kMedia['source'] = $kAttrib['SOURCE'];
  480.  
  481.               // Compatibility with the AP Usenet feed - note that this is a non
  482.               // standard attribute and is NOT a part of NITF standards
  483.  
  484.               } elseif (!empty($kAttrib['DATA-LOCATION'])) {
  485.  
  486.                   $this->_kMedia['source'] = $kAttrib['DATA-LOCATION'];
  487.  
  488.               }
  489.               
  490.               $this->_kMedia['mime-type'] = $kAttrib['MIME-TYPE'];
  491.               break;
  492.               
  493.            case 'MEDIA-OBJECT':
  494.               $this->_kMedia['encoding'] = $kAttrib['ENCODING'];
  495.               break;
  496.               
  497.            case 'MEDIA-METADATA':
  498.               if (!empty($kAttrib['NAME'])) {
  499.  
  500.                  $this->_kMedia[$kAttrib['NAME']] = $kAttrib['VALUE'];
  501.  
  502.               }
  503.               break;
  504.  
  505.            case 'PUBDATA':
  506.               foreach ($kAttrib as $sKey => $sValue) {
  507.                   
  508.                   $this->m_kPubData[strtolower($sKey)] = $sValue;
  509.  
  510.               }
  511.               break;
  512.  
  513.            case 'DOC-ID':
  514.               $this->m_kDocData['doc-id'] = $kAttrib['ID-STRING'];
  515.               break;
  516.  
  517.            // The list of keywords or phrases are just added to the array of
  518.            // keywords.
  519.  
  520.            case 'KEYWORD':
  521.               if (empty($this->m_kDocData['key-list'])) {
  522.  
  523.                   $this->m_kDocData['key-list'] = array();
  524.  
  525.               }
  526.  
  527.               array_push($this->m_kDocData['key-list'], $kAttrib['KEY']);
  528.               break;
  529.  
  530.            // The release, expiration, and issuing dates of this article. The
  531.            // ISO-8601 time stamp settings are preserved, but you can use the
  532.            // magic function strtotime() to convert these to time stamp values.
  533.  
  534.            case 'DATE.RELEASE':
  535.            case 'DATE.EXPIRE':
  536.            case 'DATE.ISSUE':
  537.               if (!empty($kAttrib['NORM'])) {
  538.  
  539.                   $sName = strtolower($sName);
  540.                   $this->m_kDocData[$sName] = $kAttrib['NORM'];
  541.                   
  542.               }
  543.               break;
  544.               
  545.            case 'REVISION-HISTORY':
  546.               array_push($this->m_akRevisions, array_change_key_case($kAttrib, CASE_LOWER));
  547.               break;
  548.               
  549.         }
  550.  
  551.     }
  552.  
  553.     /**
  554.     * Called when a tag element ends
  555.     *
  556.     * @param object
  557.     * The parser object parsing the XML data
  558.     *
  559.     * @param string
  560.     * The name of the tag element that has just ended
  561.     *
  562.     * @access private
  563.     */
  564.     function EndHandler( $oParser, $sName )
  565.     {
  566.         switch ( $sName ) {
  567.  
  568.            case 'HL1':
  569.               $this->m_kHedlines['HL1'] = trim($this->m_kHedlines['HL1']);
  570.               break;
  571.  
  572.            case 'HL2':
  573.               array_push($this->m_kHedlines['HL2'], trim($this->_sHedline));
  574.               unset($this->_sHedline);
  575.               break;
  576.  
  577.            case 'P':
  578.               if (isset($this->_bIsLede)) {
  579.  
  580.                   array_unshift($this->m_aContent, trim($this->_sContent));
  581.                   unset($this->_bIsLede);
  582.                   
  583.               } else {
  584.  
  585.                   array_push($this->m_aContent, trim($this->_sContent));
  586.                   
  587.               }
  588.               unset($this->_sContent);
  589.               break;
  590.               
  591.            case 'MEDIA':
  592.               array_push($this->m_aMedia, $this->_kMedia);
  593.               unset($this->_kMedia);
  594.               break;
  595.               
  596.         }
  597.         
  598.         array_pop($this->m_aParentTags);
  599.     }
  600.  
  601.     /**
  602.     * Handles CDATA sections from the XML document during processing
  603.     *
  604.     * @param object
  605.     * The XML parser instance inherited from the XML_Parser class
  606.     *
  607.     * @param string
  608.     * The data chunk to be processed from the parser
  609.     *
  610.     * @access private
  611.     */
  612.     function cdataHandler( $oParser, $sData )
  613.     {
  614.         if (!in_array('MEDIA-OBJECT', $this->m_aParentTags)) {
  615.  
  616.             $sData = preg_replace('#\s+#', ' ', $sData);
  617.             
  618.         }
  619.                 
  620.         // Elements that can be found in the BODY.HEAD section of the NITF
  621.         // document are defined in this handler.
  622.         
  623.         if (in_array('BODY.HEAD', $this->m_aParentTags)) {
  624.  
  625.            // We don't care if they use other attribute items, we just want the
  626.            // textual version of the byline. Other attributes are appended to
  627.            // the byline data.
  628.  
  629.            if (in_array('BYLINE', $this->m_aParentTags)) {
  630.  
  631.               if (in_array('BYTTL', $this->m_aParentTags)) {
  632.  
  633.                  $this->m_kByline['title'] .= $sData;
  634.                  return;
  635.                  
  636.               }
  637.               
  638.               $this->m_kByline['author'] .= $sData;
  639.               return;
  640.  
  641.            }
  642.  
  643.            // Generally, the distributor is the same as the company supplying
  644.            // the content. However, this is not always the case (the AP, for
  645.            // example).
  646.  
  647.            if (in_array('DISTRIBUTOR', $this->m_aParentTags)) {
  648.  
  649.                $this->m_sDistributor .= $sData;
  650.                return;
  651.  
  652.            }
  653.            
  654.            // The location where the story pertains too.
  655.  
  656.            if (in_array('DATELINE', $this->m_aParentTags)) {
  657.  
  658.                if (in_array('LOCATION', $this->m_aParentTags)) {
  659.  
  660.                    $this->m_sLocation .= $sData;
  661.  
  662.                }
  663.                return;
  664.            }
  665.            
  666.            // There are only two possibilities for hedlines, the main headline
  667.            // or a subheadline.
  668.  
  669.            if (in_array('HEDLINE', $this->m_aParentTags)) {
  670.  
  671.                if (in_array('HL2', $this->m_aParentTags)) {
  672.  
  673.                   $this->_sHedline .= $sData;
  674.                   
  675.                } else {
  676.  
  677.                    $this->m_kHedlines['HL1'] .= $sData;
  678.  
  679.                }
  680.  
  681.            }
  682.            return;
  683.  
  684.         }
  685.  
  686.         // The article content, including the lead and following paragraphs, can
  687.         // be found in this section of the XML document.
  688.  
  689.         if (in_array('BODY.CONTENT', $this->m_aParentTags)) {
  690.  
  691.             if (in_array('MEDIA', $this->m_aParentTags)) {
  692.  
  693.                 // The media caption for the currently selected media element.
  694.  
  695.                 if (in_array('MEDIA-CAPTION', $this->m_aParentTags)) {
  696.  
  697.                     $this->_kMedia['caption'] .= $sData;
  698.                     return;
  699.  
  700.                 }
  701.  
  702.                 if (in_array('MEDIA-OBJECT', $this->m_aParentTags)) {
  703.  
  704.                     $this->_kMedia['data'] .= $sData;
  705.                     return;
  706.  
  707.                 }
  708.  
  709.             }
  710.             
  711.             // A paragraph element was found.
  712.  
  713.             if (in_array('P', $this->m_aParentTags)) {
  714.                 
  715.                 $this->_sContent .= $sData;
  716.                 return;
  717.                 
  718.             }
  719.  
  720.         }
  721.         
  722.         // The <body.end> tag has two primary elements, <taglines> and the free
  723.         // form <bibliography> tags.
  724.         
  725.         if (in_array('BODY.END', $this->m_aParentTags)) {
  726.  
  727.             if (in_array('TAGLINE', $this->m_aParentTags)) {
  728.  
  729.                $this->m_sTagline .= $sData;
  730.                return;
  731.                
  732.             }
  733.             
  734.             if (in_array('BIBLIOGRAPHY', $this->m_aParentTags)) {
  735.  
  736.  
  737.                $this->m_sBibliography .= $sData;
  738.  
  739.             }
  740.  
  741.         }
  742.  
  743.     }
  744.  
  745. }
  746.  
  747. ?>
  748.